{ "cells": [ { "cell_type": "markdown", "metadata": { "scrolled": false }, "source": [ "# 副本与视图\n", "在 Numpy 中,尤其是在做数组运算或数组操作时,返回结果不是数组的 **副本** 就是 **视图**。\n", "\n", "在 Numpy 中,所有赋值运算不会为数组和数组中的任何元素创建副本。\n", "\n", "\n", "- `numpy.ndarray.copy()` 函数创建一个副本。 对副本数据进行修改,不会影响到原始数据,它们物理内存不在同一位置。\n", "\n", "【例】\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n", "y = x\n", "y[0] = -1\n", "print(x)\n", "# [-1 2 3 4 5 6 7 8]\n", "print(y)\n", "# [-1 2 3 4 5 6 7 8]\n", "\n", "x = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n", "y = x.copy()\n", "y[0] = -1\n", "print(x)\n", "# [1 2 3 4 5 6 7 8]\n", "print(y)\n", "# [-1 2 3 4 5 6 7 8]\n", "```\n", "\n", "\n", "\n", "【例】数组切片操作返回的对象只是原数组的视图。\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "y = x\n", "y[::2, :3:2] = -1\n", "print(x)\n", "# [[-1 12 -1 14 15]\n", "# [16 17 18 19 20]\n", "# [-1 22 -1 24 25]\n", "# [26 27 28 29 30]\n", "# [-1 32 -1 34 35]]\n", "print(y)\n", "# [[-1 12 -1 14 15]\n", "# [16 17 18 19 20]\n", "# [-1 22 -1 24 25]\n", "# [26 27 28 29 30]\n", "# [-1 32 -1 34 35]]\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "y = x.copy()\n", "y[::2, :3:2] = -1\n", "print(x)\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [21 22 23 24 25]\n", "# [26 27 28 29 30]\n", "# [31 32 33 34 35]]\n", "print(y)\n", "# [[-1 12 -1 14 15]\n", "# [16 17 18 19 20]\n", "# [-1 22 -1 24 25]\n", "# [26 27 28 29 30]\n", "# [-1 32 -1 34 35]]\n", "```\n", "\n", "\n", "# 索引与切片\n", "\n", "数组索引机制指的是用方括号([])加序号的形式引用单个数组元素,它的用处很多,比如抽取元素,选取数组的几个元素,甚至为其赋一个新值。\n", "\n", "## 整数索引\n", "\n", "【例】要获取数组的单个元素,指定元素的索引即可。\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n", "print(x[2]) # 3\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "print(x[2]) # [21 22 23 24 25]\n", "print(x[2][1]) # 22\n", "print(x[2, 1]) # 22\n", "```\n", "\n", "## 切片索引\n", "\n", "切片操作是指抽取数组的一部分元素生成新数组。对 python **列表**进行切片操作得到的数组是原数组的**副本**,而对 **Numpy** 数据进行切片操作得到的数组则是指向相同缓冲区的**视图**。\n", "\n", "\n", "如果想抽取(或查看)数组的一部分,必须使用切片语法,也就是,把几个用冒号( `start:stop:step` )隔开的数字置于方括号内。\n", "\n", "为了更好地理解切片语法,还应该了解不明确指明起始和结束位置的情况。如省去第一个数字,numpy 会认为第一个数字是0;如省去第二个数字,numpy 则会认为第二个数字是数组的最大索引值;如省去最后一个数字,它将会被理解为1,也就是抽取所有元素而不再考虑间隔。\n", "\n", "\n", "【例】对一维数组的切片\n", "\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n", "print(x[0:2]) # [1 2]\n", "#用下标0~5,以2为步长选取数组\n", "print(x[1:5:2]) # [2 4]\n", "print(x[2:]) # [3 4 5 6 7 8]\n", "print(x[:2]) # [1 2]\n", "print(x[-2:]) # [7 8]\n", "print(x[:-2]) # [1 2 3 4 5 6]\n", "print(x[:]) # [1 2 3 4 5 6 7 8]\n", "#利用负数下标翻转数组\n", "print(x[::-1]) # [8 7 6 5 4 3 2 1]\n", "```\n", "\n", "【例】对二维数组切片\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "print(x[0:2])\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]]\n", "\n", "print(x[1:5:2])\n", "# [[16 17 18 19 20]\n", "# [26 27 28 29 30]]\n", "\n", "print(x[2:])\n", "# [[21 22 23 24 25]\n", "# [26 27 28 29 30]\n", "# [31 32 33 34 35]]\n", "\n", "print(x[:2])\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]]\n", "\n", "print(x[-2:])\n", "# [[26 27 28 29 30]\n", "# [31 32 33 34 35]]\n", "\n", "print(x[:-2])\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [21 22 23 24 25]]\n", "\n", "print(x[:])\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [21 22 23 24 25]\n", "# [26 27 28 29 30]\n", "# [31 32 33 34 35]]\n", "\n", "print(x[2, :]) # [21 22 23 24 25]\n", "print(x[:, 2]) # [13 18 23 28 33]\n", "print(x[0, 1:4]) # [12 13 14]\n", "print(x[1:4, 0]) # [16 21 26]\n", "print(x[1:3, 2:4])\n", "# [[18 19]\n", "# [23 24]]\n", "\n", "print(x[:, :])\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [21 22 23 24 25]\n", "# [26 27 28 29 30]\n", "# [31 32 33 34 35]]\n", "\n", "print(x[::2, ::2])\n", "# [[11 13 15]\n", "# [21 23 25]\n", "# [31 33 35]]\n", "\n", "print(x[::-1, :])\n", "# [[31 32 33 34 35]\n", "# [26 27 28 29 30]\n", "# [21 22 23 24 25]\n", "# [16 17 18 19 20]\n", "# [11 12 13 14 15]]\n", "\n", "print(x[:, ::-1])\n", "# [[15 14 13 12 11]\n", "# [20 19 18 17 16]\n", "# [25 24 23 22 21]\n", "# [30 29 28 27 26]\n", "# [35 34 33 32 31]]\n", "```\n", "\n", "\n", "通过对每个以逗号分隔的维度执行单独的切片,你可以对多维数组进行切片。因此,对于二维数组,我们的第一片定义了行的切片,第二片定义了列的切片。\n", "\n", "【例】\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "print(x)\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [21 22 23 24 25]\n", "# [26 27 28 29 30]\n", "# [31 32 33 34 35]]\n", "\n", "x[0::2, 1::3] = 0\n", "print(x)\n", "# [[11 0 13 14 0]\n", "# [16 17 18 19 20]\n", "# [21 0 23 24 0]\n", "# [26 27 28 29 30]\n", "# [31 0 33 34 0]]\n", "```\n", "\n", "## dots 索引\n", "\n", "NumPy 允许使用`...`表示足够多的冒号来构建完整的索引列表。\n", "\n", "比如,如果 `x` 是 5 维数组:\n", "\n", "- `x[1,2,...]` 等于 `x[1,2,:,:,:]`\n", "- `x[...,3]` 等于 `x[:,:,:,:,3]` \n", "- `x[4,...,5,:]` 等于 `x[4,:,:,5,:]`\n", "\n", "【例】\n", "```python\n", "import numpy as np\n", "\n", "x = np.random.randint(1, 100, [2, 2, 3])\n", "print(x)\n", "# [[[ 5 64 75]\n", "# [57 27 31]]\n", "# \n", "# [[68 85 3]\n", "# [93 26 25]]]\n", "\n", "print(x[1, ...])\n", "# [[68 85 3]\n", "# [93 26 25]]\n", "\n", "print(x[..., 2])\n", "# [[75 31]\n", "# [ 3 25]]\n", "```\n", "\n", "\n", "\n", "## 整数数组索引\n", "\n", "【例】方括号内传入多个索引值,可以同时选择多个元素。\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n", "r = [0, 1, 2]\n", "print(x[r])\n", "# [1 2 3]\n", "\n", "r = [0, 1, -1]\n", "print(x[r])\n", "# [1 2 8]\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "\n", "r = [0, 1, 2]\n", "print(x[r])\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [21 22 23 24 25]]\n", "\n", "r = [0, 1, -1]\n", "print(x[r])\n", "\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [31 32 33 34 35]]\n", "\n", "r = [0, 1, 2]\n", "c = [2, 3, 4]\n", "y = x[r, c]\n", "print(y)\n", "# [13 19 25]\n", "```\n", "\n", "【例】\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n", "r = np.array([[0, 1], [3, 4]])\n", "print(x[r])\n", "# [[1 2]\n", "# [4 5]]\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "\n", "r = np.array([[0, 1], [3, 4]])\n", "print(x[r])\n", "# [[[11 12 13 14 15]\n", "# [16 17 18 19 20]]\n", "#\n", "# [[26 27 28 29 30]\n", "# [31 32 33 34 35]]]\n", "\n", "# 获取了 5X5 数组中的四个角的元素。\n", "# 行索引是 [0,0] 和 [4,4],而列索引是 [0,4] 和 [0,4]。\n", "r = np.array([[0, 0], [4, 4]])\n", "c = np.array([[0, 4], [0, 4]])\n", "y = x[r, c]\n", "print(y)\n", "# [[11 15]\n", "# [31 35]]\n", "```\n", "\n", "【例】可以借助切片`:`与整数数组组合。\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "\n", "y = x[0:3, [1, 2, 2]]\n", "print(y)\n", "# [[12 13 13]\n", "# [17 18 18]\n", "# [22 23 23]]\n", "```\n", "\n", "- `numpy. take(a, indices, axis=None, out=None, mode='raise')` Take elements from an array along an axis.\n", "\n", "【例】\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n", "r = [0, 1, 2]\n", "print(np.take(x, r))\n", "# [1 2 3]\n", "\n", "r = [0, 1, -1]\n", "print(np.take(x, r))\n", "# [1 2 8]\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "\n", "r = [0, 1, 2]\n", "print(np.take(x, r, axis=0))\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [21 22 23 24 25]]\n", "\n", "r = [0, 1, -1]\n", "print(np.take(x, r, axis=0))\n", "# [[11 12 13 14 15]\n", "# [16 17 18 19 20]\n", "# [31 32 33 34 35]]\n", "\n", "r = [0, 1, 2]\n", "c = [2, 3, 4]\n", "y = np.take(x, [r, c])\n", "print(y)\n", "# [[11 12 13]\n", "# [13 14 15]]\n", "```\n", "\n", "应注意:使用切片索引到numpy数组时,生成的数组视图将始终是原始数组的子数组,\n", " 但是整数数组索引,不是其子数组,是形成新的数组。\n", "切片索引\n", "```python\n", "import numpy as np\n", "\n", "a=np.array([[1,2],[3,4],[5,6]])\n", "b=a[0:1,0:1]\n", "b[0,0]=2\n", "print(a[0,0]==b)\n", "#[[True]]\n", "```\n", "整数数组索引\n", "```python\n", "import numpy as np\n", "\n", "a=np.array([[1,2],[3,4],[5,6]])\n", "b=a[0,0]\n", "b=2\n", "print(a[0,0]==b)\n", "#False\n", "```\n", "\n", "## 布尔索引\n", "\n", "我们可以通过一个布尔数组来索引目标数组。\n", "\n", "【例】\n", "\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n", "y = x > 5\n", "print(y)\n", "# [False False False False False True True True]\n", "print(x[x > 5])\n", "# [6 7 8]\n", "\n", "x = np.array([np.nan, 1, 2, np.nan, 3, 4, 5])\n", "y = np.logical_not(np.isnan(x))\n", "print(x[y])\n", "# [1. 2. 3. 4. 5.]\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "y = x > 25\n", "print(y)\n", "# [[False False False False False]\n", "# [False False False False False]\n", "# [False False False False False]\n", "# [ True True True True True]\n", "# [ True True True True True]]\n", "print(x[x > 25])\n", "# [26 27 28 29 30 31 32 33 34 35]\n", "```\n", "\n", "【例】\n", "```python\n", "import numpy as np\n", "\n", "import matplotlib.pyplot as plt\n", "\n", "x = np.linspace(0, 2 * np.pi, 50)\n", "y = np.sin(x)\n", "print(len(x)) # 50\n", "plt.plot(x, y)\n", "\n", "mask = y >= 0\n", "print(len(x[mask])) # 25\n", "print(mask)\n", "'''\n", "[ True True True True True True True True True True True True\n", " True True True True True True True True True True True True\n", " True False False False False False False False False False False False\n", " False False False False False False False False False False False False\n", " False False]\n", "'''\n", "plt.plot(x[mask], y[mask], 'bo')\n", "\n", "mask = np.logical_and(y >= 0, x <= np.pi / 2)\n", "print(mask)\n", "'''\n", "[ True True True True True True True True True True True True\n", " True False False False False False False False False False False False\n", " False False False False False False False False False False False False\n", " False False False False False False False False False False False False\n", " False False]\n", "'''\n", "\n", "plt.plot(x[mask], y[mask], 'go')\n", "plt.show()\n", "```\n", "\n", "![](https://img-blog.csdnimg.cn/20191109183704335.png)\n", "\n", "我们利用这些条件来选择图上的不同点。蓝色点(在图中还包括绿点,但绿点掩盖了蓝色点),显示值 大于0 的所有点。绿色点表示值 大于0 且 小于0.5π 的所有点。\n", "\n", "\n", "\n", "\n", "---\n", "# 数组迭代\n", "\n", "除了for循环,Numpy 还提供另外一种更为优雅的遍历方法。\n", "\n", "- `apply_along_axis(func1d, axis, arr)` Apply a function to 1-D slices along the given axis.\n", "\n", "【例】\n", "```python\n", "import numpy as np\n", "\n", "x = np.array([[11, 12, 13, 14, 15],\n", " [16, 17, 18, 19, 20],\n", " [21, 22, 23, 24, 25],\n", " [26, 27, 28, 29, 30],\n", " [31, 32, 33, 34, 35]])\n", "\n", "y = np.apply_along_axis(np.sum, 0, x)\n", "print(y) # [105 110 115 120 125]\n", "y = np.apply_along_axis(np.sum, 1, x)\n", "print(y) # [ 65 90 115 140 165]\n", "\n", "y = np.apply_along_axis(np.mean, 0, x)\n", "print(y) # [21. 22. 23. 24. 25.]\n", "y = np.apply_along_axis(np.mean, 1, x)\n", "print(y) # [13. 18. 23. 28. 33.]\n", "\n", "\n", "def my_func(x):\n", " return (x[0] + x[-1]) * 0.5\n", "\n", "\n", "y = np.apply_along_axis(my_func, 0, x)\n", "print(y) # [21. 22. 23. 24. 25.]\n", "y = np.apply_along_axis(my_func, 1, x)\n", "print(y) # [13. 18. 23. 28. 33.]\n", "```\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.10" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": { "height": "calc(100% - 180px)", "left": "10px", "top": "150px", "width": "307.2px" }, "toc_section_display": true, "toc_window_display": true }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }